package com.poster.service.impl;

import com.auth0.jwt.interfaces.Claim;
import com.poster.constant.JWTKeys;
import com.poster.entity.po.Role;
import com.poster.entity.po.RolePermission;
import com.poster.entity.query.RoleQuery;
import com.poster.enums.PermissionType;
import com.poster.enums.ResultCode;
import com.poster.exceptions.BusinessException;
import com.poster.mappers.RoleMapper;
import com.poster.mappers.RolePermissionMapper;
import com.poster.service.IRoleService;
import com.poster.utils.JWTUtils;
import com.poster.utils.RedisUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.poster.constant.RedisConstant.*;

@Slf4j
@Service
public class RoleService implements IRoleService {

    private final RoleMapper roleMapper;

    private final RolePermissionMapper rolePermissionMapper;
    
    private final RedisUtils redisUtils;

    private final JWTUtils jwtUtils;

    public RoleService(RoleMapper roleMapper, RolePermissionMapper rolePermissionMapper, RedisUtils redisUtils, JWTUtils jwtUtils) {
        this.roleMapper = roleMapper;
        this.rolePermissionMapper = rolePermissionMapper;
        this.redisUtils = redisUtils;
        this.jwtUtils = jwtUtils;
    }



    @Override
    public void create(Integer creatorId, String roleName, String introduction) {
        if (creatorId == null || roleName == null){
            throw new BusinessException(ResultCode.PARAM_IS_BLANK);
        }

        Role bean = new Role();
        bean.setName(roleName);
        bean.setIntroduction(introduction);
        bean.setCreateBy(creatorId);
        bean.setCreateAt(LocalDateTime.now());

        try{
            roleMapper.insert(bean);
        } catch (DuplicateKeyException e) {
            throw new BusinessException(ResultCode.PARAM_IS_INVALID, "角色名称 " + roleName + "已经存在");
        }
    }

    @Override
    public void editInfo(Integer editorId, Integer roleId, String name, String introduction) {
        if (editorId == null){
            throw new BusinessException(ResultCode.PARAM_IS_BLANK);
        }
        if (name == null && introduction == null){
            return;
        }

        if (!roleMapper.existByName(name)){
            throw new BusinessException(ResultCode.PARAM_IS_INVALID);
        }

        Role bean = new Role();
        bean.setName(name);
        bean.setIntroduction(introduction);

        RoleQuery query = new RoleQuery();
        query.setId(roleId);

        roleMapper.updateByParam(bean, query);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void bindPermission(Integer creator, Integer roleId, List<Integer> permissionIds) {

        if (creator == null || roleId == null
                || permissionIds == null || permissionIds.isEmpty()
        ){
            throw new BusinessException(ResultCode.PARAM_IS_BLANK);
        }

        if (!roleMapper.existById(roleId)){
            throw new BusinessException(ResultCode.PARAM_IS_INVALID);
        }
        // TODO 检查创建者是否存在

        rolePermissionMapper.deleteByRoleId(roleId);

        List<RolePermission> beanList = permissionIds.stream().map(
                it -> {
                    RolePermission bean = new RolePermission();
                    bean.setCreateAt(LocalDateTime.now());
                    bean.setCreateBy(creator);
                    bean.setPermissionId(it);
                    bean.setRoleId(roleId);
                    return bean;
                }
        ).toList();

        rolePermissionMapper.insertBatch(beanList);
    }

    public Map<String, Claim> authentication(HttpServletRequest request, PermissionType permissionType) {
        String token = request.getHeader("authorization");
        Map<String, Claim> claims = jwtUtils.verifyAndGetJWTClaims(token);

        Claim userIdClaim = claims.get(JWTKeys.USER_ID);
        Claim roleIdClaim = claims.get(JWTKeys.ROLE_ID);
        if (roleIdClaim == null){
            throw new BusinessException(ResultCode.INTERFACE_FORBID_VISIT);
        }

        Integer roleId = roleIdClaim.asInt();
        if (roleId == null){
            throw new BusinessException(ResultCode.INTERFACE_FORBID_VISIT);
        }

        // TODO redis权限验证
        return claims;
    }

    public Map<String, Claim> authentication(HttpServletRequest request) {
        String token = request.getHeader("authorization");
        return jwtUtils.verifyAndGetJWTClaims(token);
    }


    @Override
    public void saveRolePermissionMap2Redis() {

        if (redisUtils.exists(ROLE_PERMISSION_MAP)){
            redisUtils.del(ROLE_PERMISSION_MAP);
        }

        List<Role> roles = roleMapper.selectList(null);

        List<RolePermission> rolePermissions = rolePermissionMapper.selectPermissionCodeList(null);

        Map<Integer , List<String>> rolePermissionMap =
            rolePermissions.stream().
                collect(
                    // 用 roleId作为key, 然后生成权限列表
                    Collectors.groupingBy(
                            RolePermission::getId,
                            Collectors.mapping(RolePermission::getPermissionCode, Collectors.toList()
                        )
                    )
                );

        // 兜底 当角色没有权限的时候也放进去
        roles.forEach(r -> rolePermissionMap.putIfAbsent(r.getId(), List.of()));

        // TODO 定时刷新缓存

//        rolePermissionMap.forEach((roleId, permissionCodes) -> {
//            permissionCodes.forEach(code -> {
//                redisUtils.set(link(ROLE_PERMISSION_MAP, List.of(roleId.toString(), code) ), "", EXPIRE_ONE_DAY);  // 空串即可，存在即有权
//            });
//        });
    }

}
